<?php

class comments
{
   private $comments = NULL;

   private $authority = TRUE; // If TRUE - only authorized users can comment
   private $moderate  = TRUE; // If TRUE - all comments should be premoderated


   public function __construct($params = NULL)
   {
      $this->settings($params);
   }

   /**
    * Comments class settings setter
    * 
    * @param array $params
    */
   public function settings($params)
   {
      if(!empty($params))
      {
         foreach($params AS $key=>$value)
         {
            switch($key)
            {
               case 'authority':
               case 'moderate':
                  $this->{$key} = (bool)$value;
                  break;
            }
         }
      }
   }


   /**
    * Add new comment
    * 
    * @param array $data
    * @return boolean
    */
   public function add($data)
   {
      $DB     = database::getInstance();
      $FILTER = new filters();
      $USERS  = users::getInstance();

      $data['uid']  = session::user()                                    ? session::user()->id : NULL;
      $data['pcid'] = !empty($data['pcid']) && is_numeric($data['pcid']) ? $data['pcid']       : 0;

      if(empty($data['aid']) || empty($data['message']) || (empty($data['uid']) && $this->authority))
         return FALSE;

      $DB->DB_StartTransaction();
      
      $positions = $this->getTreePosition($data['aid'], $data['pcid']);
      $ip        = get_ip();
      $active    = $this->moderate ? 0 : 1;
      $data['message'] = $FILTER->ClearHtml($data['message']);

      $sql = 'INSERT INTO `meccano_comments` (`aid`, `uid`, `active`, `cdate`, `ip`, `lt`, `rt`, `level`, `comment`)
         VALUES (%i, '. ($data['uid'] ? $data['uid'] : 'NULL') .', "'. $active .'", NOW(), INET_ATON("'. $ip .'"), '. $positions['lt'] .', '. $positions['rt'] .', '. $positions['level'] .', "%s")';
      $DB->DB_QueryBuilder($sql, array($data['aid'], $data['message']));

      if($DB->DB_Query())
      {
         $DB->DB_EndTransaction();
         return $DB->DB_LastID();
      }

      return FALSE;
   }


   /**
    * Delete comments by ID, and its chield
    *
    * @param integer $id
    * @return boolean
    */
   public function delete($id)
   {
      if(intval($id))
      {
         $id      = intval($id);
         $DB      = database::getInstance();
         $DB->sql = 'SELECT `lt`, `rt`, `aid` FROM `meccano_comments` WHERE `id` = '. $id;
         $ltrt    = $DB->DB_FetchFlat();
         if(!empty($ltrt))
         {
            $DB->sql = 'DELETE FROM `meccano_comments` WHERE `lt` >= '. $ltrt['lt'] .' AND `rt` <= '. $ltrt['rt'] .' AND `aid` = '. $ltrt['aid'];
            $DB->DB_Query();
            $DB->sql = 'UPDATE `meccano_comments` SET 
               `lt` = IF(`lt` > '. $ltrt['lt'] .', `lt` - '. ($ltrt['rt'] - $ltrt['lt'] + 1) .', `lt`),
               `rt` = IF(`rt` > '. $ltrt['lt'] .', `rt` - '. ($ltrt['rt'] - $ltrt['lt'] + 1) .', `rt`)
               WHERE `aid` = '. $ltrt['aid'];
            $DB->DB_Query();

            return TRUE;
         }
      }

      return FALSE;
   }


   /**
    * Switch comment to active state
    *
    * @param integer $id
    * @return boolean
    */
   public function activeOn($id)
   {
      if(intval($id))
      {
         $id = intval($id);
         $DB = database::getInstance();
         $DB->sql = 'UPDATE `meccano_comments` SET `active` = "1" WHERE `id` = '. $id;
         return $DB->DB_Query();
      }

      return FALSE;
   }


   /**
    * Switch comment to inactive state
    * @param integer $id
    * @return boolean
    */
   public function activeOff($id)
   {
      if(intval($id))
      {
         $id = intval($id);
         $DB = database::getInstance();
         $DB->sql = 'UPDATE `meccano_comments` SET `active` = "0" WHERE `id` = '. $id;
         return $DB->DB_Query();
      }

      return FALSE;
   }


   public function load($aid, $all = FALSE)
   {
      (int)$aid;
      if($aid)
      {
         $DB = database::getInstance();

         $sql = 'SELECT `id`, `aid`, `uid`, `active`, `cdate`, INET_NTOA(`ip`) AS `ip`, `lt`, `rt`, `level`, `comment`
            FROM `meccano_comments` WHERE `aid` = '. $aid;
         if(!$all) $sql .= ' AND `active` = "1"';
         $sql .= ' ORDER BY `lt` ASC';
         $DB->sql  = $sql;
         $comments = $DB->DB_Fetch();
         if($comments)
         {
            $comments = $this->attacheUsers($comments);
            $this->comments = $this->buildTree($comments, $all);
            $this->comments = array_reverse($this->comments);

            return $this->comments;
         }
      }

      return FALSE;
   }

   public function countComments($aid, $all = FALSE)
   {
      $return_as = 'integer';
      if(is_array($aid)) $return_as = 'array';
      $aid = (array)$aid;
      $aid = array_filter($aid, 'is_numeric');
      $c = 0;
      if(!empty($aid))
      {
         $DB = database::getInstance();
         $sql = 'SELECT `aid`, COUNT(*) AS `c` FROM `meccano_comments` WHERE `aid` IN ('. implode(',', $aid) .')';
         if(!$all) $sql .= ' AND `active` = "1"';
         $sql .= ' GROUP BY `aid`';
         $DB->sql = $sql;
         $DB->DB_Fetch();
         $counts = array();
         for($i=0, $t=$DB->rows; $i<$t; $i++)
         {
            $counts[$DB->fetched[$i]['aid']] = $DB->fetched[$i]['c'];
         }

         $c = array();
         for($i=0, $t=sizeof($aid); $i<$t; $i++)
         {
            $c[$aid[$i]] = empty($counts[$aid[$i]]) ? 0 : $counts[$aid[$i]];
         }
         if($return_as == 'integer')
         {
            $c = reset($c);
         }
      }

      return $c;
   }

   private function getTreePosition($aid, $pcid)
   {
      $DB  = database::getInstance();
      $sql = 'SELECT `lt`, `rt`, `level` FROM `meccano_comments` WHERE `aid` = %i AND `id` = %i';
      $DB->DB_QueryBuilder($sql, array($aid, $pcid));
      $positions = $DB->DB_FetchFlat();

      if(!empty($positions))
      {
         $DB->sql = 'UPDATE `meccano_comments` SET
            `lt` = IF(`lt` > '. $positions['rt'] .', `lt` + 2, `lt`),
            `rt` = IF(`rt` >= '. $positions['rt'] .', `rt` + 2, `rt`)
            WHERE `aid` = '. (int)$aid;
         $DB->DB_Query();

         $positions['lt'] = $positions['rt'];
         $positions['rt']++;
         $positions['level']++;

         return $positions;
      }

      $positions = array();
      $positions['lt']    = $DB->DB_GetNextID('rt', 'meccano_comments', '`aid` = '. (int)$aid);
      $positions['rt']    = $positions['lt'] + 1;
      $positions['level'] = 1;

      return $positions;
   }


   private function buildTree(&$comments, $all = FALSE, $parent = NULL)
   {
      $comments_tree = array();
      $comment       = NULL;

      while(!empty($comments))
      {
         $top_comment = reset($comments);

         if(!empty($comment) && $comment['level'] < $top_comment['level'])
         {
            $comment['comments'] = $this->buildTree($comments, $all, $comment['id']);
            $comments_tree[$comment['id']] = $comment;
         }

         if(empty($comments)) continue;
         $top_comment = reset($comments);
         if(!empty($comment) && $comment['level'] > $top_comment['level'])
         {
            break;
         }

         $comment = array_shift($comments);
         if(!$all && $comment['active'] == 0) continue;
         $comment['comments'] = array();
         $comment['parent']   = !empty($parent) ? $parent : NULL;
         unset($comment['lt'], $comment['rt']);

         $comments_tree[$comment['id']] = $comment;
      }

      return $comments_tree;
   }


   private function attacheUsers($comments)
   {
      $users = array();
      for($i=0, $t=sizeof($comments); $i<$t; $i++)
      {
         if($comments[$i]['active'] && $comments[$i]['uid'])
         {
            if(empty($users[$comments[$i]['uid']])) $users[$comments[$i]['uid']] = array();
            $users[$comments[$i]['uid']][] = $i;
         }
      }

      if(!empty($users))
      {
         $USRS = users::getInstance();
         $u = $USRS->getUsers(array(
            'u' => array('id' => array_keys($users))
         ), TRUE);

         if(!empty($u))
         {
            foreach($u AS $commentator)
            {
               $u_name   = $commentator->name .' '. $commentator->surname;
               $u_id     = $commentator->id;
               $u_type   = $commentator->type;
               $u_images = $commentator->pics();
               foreach($users[$u_id] AS $i)
               {
                  $comments[$i]['user'] = array(
                     'name'   => $u_name,
                     'id'     => $u_id,
                     'type'   => $u_type,
                     'images' => $u_images
                  );
               }
            }
         }
      }

      return $comments;
   }
}